package com.skyline.common.reflection;

import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 方法操作从句类
 * 
 * @author wuqh
 * 
 */
public class MethodUtils {
	private static final Logger LOGGER = LoggerFactory.getLogger(MethodUtils.class);

	/**
	 * 查找指定类中的所有方法（包括父类和接口中的方法），并使用方法回调接口对这些方法进行处理。
	 * <p>
	 * 方法被回调前会通过{@link MethodFilter}进行判断，是否需要被回调
	 * 
	 * @param clazz
	 * @param mc
	 * @param mf
	 */
	public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) throws Exception {

		// Keep backing up the inheritance hierarchy.
		Method[] methods = clazz.getDeclaredMethods();
		for (Method method : methods) {
			if (mf != null && !mf.matches(method)) {
				continue;
			}
			try {
				mc.doWith(method);
			} catch (IllegalAccessException ex) {
				throw new IllegalStateException("非法访问方法'" + method.getName() + "'：" + ex);
			}
		}
		if (clazz.getSuperclass() != null) {
			doWithMethods(clazz.getSuperclass(), mc, mf);
		} else if (clazz.isInterface()) {
			for (Class<?> superIfc : clazz.getInterfaces()) {
				doWithMethods(superIfc, mc, mf);
			}
		}
	}

	/**
	 * 方法回调接口
	 */
	public interface MethodCallback {

		/**
		 * 回调方法
		 * 
		 * @param method
		 */
		void doWith(Method method) throws Exception;
	}

	/**
	 * 方法过滤器，用于判断哪些方法会被方法回调接口执行
	 */
	public interface MethodFilter {

		/**
		 * 判断给定方法是否符合规则（不符合规则的将被过滤）
		 * 
		 * @param method
		 */
		boolean matches(Method method);
	}

	/**
	 * 预设的MethodFilter实现类，用于匹配方法中所有的非桥接方法和所有非<code>java.lang.Object</code>申明的方法
	 */
	public static final MethodFilter USER_DECLARED_METHODS = new MethodFilter() {

		public boolean matches(Method method) {
			return (!method.isBridge() && method.getDeclaringClass() != Object.class);
		}
	};

	/**
	 * 调用method方法
	 * 
	 * @param object
	 * @param method
	 * @param args
	 */
	public static Object invokeMethod(Object object, Method method, Object... args) {
		try {
			method.setAccessible(true);
			return method.invoke(object, args);
		} catch (Exception e) {
			LOGGER.warn("调用方法失败", e);
			return null;
		}

	}
}
